<?php

namespace Plugins\AdminBasic\Http;

use App\Models\Model;
use App\Util\Helper;
use Hyperf\DbConnection\Db;
use Plugins\AdminBasic\Enums\BasicSuperConfigEnumType;
use Plugins\AdminBasic\Models\BasicSuperConfig;
use Psr\SimpleCache\InvalidArgumentException;

/**
 * 获取超级配置
 */
class SuperConfig
{

    /**
     * 获取非表数据的配置
     *
     * @param string $sign
     * @param null $default
     * @param bool $latest
     * @return mixed
     * @throws InvalidArgumentException
     */
    public static function get(string $sign, $default = null, bool $latest = false): mixed
    {
        if (str_contains($sign, '.')) {
            $keys = explode('.', $sign);
            $sign = array_shift($keys);
        }

        /** @var BasicSuperConfig $superConfig */
        if ($latest) {
            $superConfig = BasicSuperConfig::where('sign', $sign)->first();
        }else{
            if (!Helper::cache()->get($sign)) {
                Helper::cache()->set($sign, BasicSuperConfig::where('sign', $sign)->first(), 60);
            }
            $superConfig = Helper::cache()->get($sign);
        }

        if (!$superConfig) {
            return $default;
        }

        $value = $superConfig->config_value;

        if (!empty($keys)) {
            return array_reduce($keys, fn ($init, $key) => $init[$key] ?? $default, $value);
        }
        if ($superConfig->type === BasicSuperConfigEnumType::Array){
            return array_column($value['content'] ?? [], 'value');
        }
        if ($superConfig->type === BasicSuperConfigEnumType::KeyValuePairs){
            return array_map(function ($v){
                if (isset($v['label']) && isset($v['value'])) {
                    $v['value'] = is_numeric($v['value']) ? (int)$v['value'] : $v['value'];
                    return $v;
                }

                $v['label'] = $v['value'];
                $v['value'] = is_numeric($v['key']) ? (int)$v['key'] : $v['key'];
                return $v;
            }, $value['content'] ?? []);
        }

        return self::selectionConfigureAnalyze($value ?: [], $superConfig->config_info, $superConfig->type === BasicSuperConfigEnumType::AdvancedArray);
    }


    private static function selectionConfigureAnalyze(array $data, array $configure, bool $isAdvancedArray): array
    {
        $configure = array_column($configure, null, 'field');

        foreach ($configure as $field => $datum) {
            if (empty($datum['extra']) || !is_array($datum['extra'])) {
                continue;
            }

            $options = self::getSelectOptions($datum['extra']);
            $mapping = array_column($options, 'label', 'value');

            if ($isAdvancedArray) {
                foreach ($data as &$item) {
                    $item[$field] = self::selectionConfigureMappingSet($item[$field] ?? null, $mapping);
                }
                continue;
            }

            $data[$field] = self::selectionConfigureMappingSet($data[$field] ?? null, $mapping);
        }

        return $data;
    }

    private static function selectionConfigureMappingSet($value, $mapping): array
    {
        if (is_array($value)) {
            $data = [];
            foreach ($value as $item) {
                $data[] = self::selectionConfigureMappingSet($item, $mapping);
            }
            return $data;
        }

        return [
            'value' => $value,
            'label' => $value ? ($mapping[$value] ?? null) : null
        ];
    }

    public static function getSelectOptions(array $options): array
    {
        if (count($options) == 1) {
            return self::remoteOptionsAnalyze($options[0]);
        }

        return self::customOptionsAnalyze($options);
    }

    private static function customOptionsAnalyze(array $options): array
    {
        return array_map(function ($item){
            list($value, $label) = explode('=', $item);
            return [
                'label' => $label,
                'value' => $value
            ];
        }, $options);
    }

    private static function remoteOptionsAnalyze(string $remoteInfo): array
    {
        if (str_contains($remoteInfo, '\\')) {
            return call_user_func("$remoteInfo::formOptions");
        }

        if (!str_contains($remoteInfo, ':')) {
            $options = self::get($remoteInfo);
            // 数组数据
            if (count($options) == count($options, COUNT_RECURSIVE)){
                return array_map(fn($v) => ['value' => $v, 'label' => $v], $options);
            }
            // 键值对
            return $options;
        }

        list($tableName, $fieldInfo) = explode(':', $remoteInfo);
        if (!str_contains($fieldInfo, '=')) {
            $options = self::get($tableName);
            // 高级数组
            return array_map(fn($v) => ['label' => $v[$fieldInfo], 'value' => $v['cid']], $options);
        }

        return self::remoteTableDataAnalyze($tableName, $fieldInfo);
    }

    private static function remoteTableDataAnalyze($tableName, $fieldInfo): array
    {
        $where = '';
        if (str_contains($fieldInfo, ';')) {
            list($fieldInfo, $where) = explode(';', $fieldInfo);
        }
        list($value, $label) = explode('=', $fieldInfo);

        $optionsQuery = Db::table($tableName)->select([$value, $label]);
        if ($where) {
            foreach (explode('&', $where) as $item) {
                list($k, $v) = explode('=', $item);
                str_contains($v, ',')
                    ? $optionsQuery->whereIn($k, explode(',', $v))
                    : $optionsQuery->where($k, $v);
            }
        }
        $options = $optionsQuery->whereNull(Model::DELETED_AT)->get()->toArray();

        foreach ($options as &$item) {
            $item = [
                'value' => $item->$value,
                'label' => $item->$label
            ];
        }

        return $options;
    }
}
